package core;

/**
 * A class that models a Register Bank of shorts
 * @author Ximo Tur ximotur at gmail dot com
 */

public class RegisterClass {
	private short registers[] = null;
	private int SP = 15;	//StackPoint
	private int maxReg = 0;
	private core.interfaces.RegisterCallbackInterface callback = null;

	/**
	 * Constructor that initiates a RegisterBank with n registers and SP as the Stack Pointer
	 * @param n the number of registers
	 * @param SP the register that will be the Stack Pointer
	 */
	public RegisterClass(int n, int SP){
		this.maxReg = n;
		this.SP = SP;
		this.registers = new short[this.maxReg];
	}
	
	/**
	 * Constructor that initiates a RegisterBank with n registers and SP as the Stack Pointer
	 * @param n the number of registers
	 * @param SP the register that will be the Stack Pointer
	 * @param callback The interface to inform about register changes.
	 */
	public RegisterClass(int n, int SP, core.interfaces.RegisterCallbackInterface callback){
		this.maxReg = n;
		this.SP = SP;
		this.registers = new short[this.maxReg];
		this.callback = callback;
	}
	/**
	 * Constructor that initiates a RegisterBank with n registers and with the Stack
	 * Pointer in the default register #15
	 * @param n the number of registers
	 */
	public RegisterClass(int n){
		this(n,n-1);
	}
	
	/**
	 * Constructor that initiates a RegisterBank of 16 registers and the Stack Pointer
	 * in register #15
	 */
	public RegisterClass(){
		this(16, 15);
	}

	/**
	 * Sets the callback object for the Register Class
	 * @param cObject The object that will act as callback object.
	 */
	public void setCallBack(core.interfaces.RegisterCallbackInterface cObject){
		this.callback = cObject;
	}

	/**
	 * Returns the content of the given register
	 * @param n is the register to be read
	 * @return is the content of the given register
	 */
	public short getRegister(int n){
		if(n>=0 && n<maxReg){
			if(this.callback != null){
				this.callback.registerAccessed(n);
			}
			return registers[n];
		}else{
			//TODO: generate an out-of-bounds exception
			return 0;
		}
	}

	/**
	 * Sets the content for a register.
	 * @param n is the number of the register to be set.
	 * @param value is the content to be set.
	 */
	public void setRegister(int n, short value){
		if(n>=0 && n<maxReg){
			if(this.callback != null){
				this.callback.registerChanged(n);
			}
			registers[n] = value;
		}else{
			//TODO: generate an out-of-bounds exception
		}
	}

	/**
	 * Returns the content of the Stack Pointer Register
	 * @return the content of the Stack Pointer Register
	 */
	public short getSP(){
		return getRegister(SP);
	}
	public short getSilentSP(){
		return(registers[SP]);
	}
	/**
	 * Sets the content for the Stack Pointer Register
	 * @param value is the content to be set.
	 */
	public void setSP(short value){
		this.setRegister(SP, value);
	}
	/**
	 * Increases the SP (for POP operations)
	 */
	public void increaseSP(){
		int aux = 0x0000FFFF & this.getSP();
		aux = aux+1;
		this.setSP((short)(aux));
	}
	/**
	 * Decreases the SP (for PUSH operations)
	 */
	public void decreaseSP(){
		int aux = 0x0000FFFF & this.getSP();
		aux = aux-1;
		this.setSP((short)(aux));
	}
	/**
	 * Returns the number of Registers on the bank
	 * @return the number of Registers on the bank
	 */
	public int getMax(){
		return(this.maxReg);
	}
	//Extremely dirty trick for java: encode two shorts into a Integer
	public java.util.Vector<java.lang.Integer> getRegisterVector(){
		java.util.Vector<java.lang.Integer> v = new java.util.Vector<java.lang.Integer>();
		for(int i=0; i<this.getMax(); i++){
			v.add(java.lang.Integer.valueOf((i<<16)|(0x0000FFFF & this.registers[i])));
		}
		return(v);
	}
}
